package com.mofum.scope.spring.web;

import com.mofum.scope.annotation.service.parser.TableScopeParser;
import com.mofum.scope.common.annotation.metadata.service.MColumnScope;
import com.mofum.scope.common.annotation.metadata.service.MTableScope;
import com.mofum.scope.common.model.Parameter;
import com.mofum.scope.common.model.Scope;
import com.mofum.scope.common.utils.ParentFieldUtils;
import com.mofum.scope.common.utils.ScopeUtils;
import com.mofum.scope.spring.web.constant.Constant;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 抽象的权限范围列切面
 *
 * @author yuyang@qxy37.com
 * @since 2019-03-20
 **/
public abstract class AbstractColumnAspectJ extends AbstractAspect {

	@Around("config()")
	public Object process(ProceedingJoinPoint joinPoint) throws Throwable {
		try {

			Object[] args=joinPoint.getArgs();
			Signature signature=joinPoint.getSignature();
			MethodSignature methodSignature=(MethodSignature) signature;
			String[] names=methodSignature.getParameterNames();
			TableScopeParser scopeParser=new TableScopeParser();
			Map<Type, MTableScope> typeMTableScopeMap=scopeParser.parseType(joinPoint.getTarget().getClass());
			MTableScope mTableScope=typeMTableScopeMap.get(joinPoint.getTarget().getClass());
			if (mTableScope == null || mTableScope.getColumns() == null || mTableScope.getColumns().length == 0) {
				return joinPoint.proceed(args);
			}
			Object[] newParams=assembleParameter(args, names, mTableScope);
			try {
				Object proceed=joinPoint.proceed(newParams);
				return proceed;
			} catch (Throwable throwable) {
				throw new RuntimeException(throwable.getMessage(), throwable);
			} finally {
				removeThreadLocal();
			}

		} catch (Throwable e) {
			getThrowableHandler().handler(e);
		}

		return null;
	}

	/**
	 * 方法执行完后执行
	 */
	protected void removeThreadLocal() {
		ScopeUtils.removeScopes();
	}

	/**
	 * 组装新的请求参数
	 * @param args 原参数
	 * @param parameterNames 对应的参数名
	 * @param mTableScope service注解上的TableScope值
	 * @return 返回组装后的参数
	 */
	protected Object[] assembleParameter(Object[] args, String[] parameterNames, MTableScope mTableScope) {
		if (args == null) {
			return args;
		}
		Object[] newParams=new Object[args.length];
		for (int i=0; i < args.length; i++) {
			Parameter parameter=new Parameter(i, parameterNames[i], args[i]);
			processParameter(parameter, mTableScope, true);
			newParams[i]=parameter.getValue();
		}
		return newParams;
	}

	protected void processParameter(Parameter parameter, MTableScope mTableScope, boolean eachNext) {

		if (parameter == null) {
			return;
		}

		Object object=parameter.getValue();

		//为空就不进行后续操作
		if (object == null) {
			return;
		}

		if (!(object instanceof List)) {
			Field field=null;
			field=ParentFieldUtils.getFieldByName(Constant.SCOPE_SCOPES, object.getClass());
			if (field != null && eachNext) {

				Object data=null;
				try {
					field.setAccessible(true);
					data=field.get(object);
					field.setAccessible(false);
				} catch (IllegalAccessException e) {
					data=null;
				}

				Parameter tempParameter=new Parameter(0, Constant.SCOPE_SCOPES, data);

				processParameter(tempParameter, mTableScope, false);

				try {
					field.setAccessible(true);
					field.set(object, tempParameter.getValue());
					field.setAccessible(false);
				} catch (IllegalAccessException e) {
					try {
						field.set(object, null);
					} catch (IllegalAccessException e1) {
					}
				}

				try {
					ScopeUtils.setScopes((List<Scope>) data);
				} catch (Throwable e) {
					//TODO
				}
			}
			return;
		}


		//参数 是 权限范围字段
		if (parameter.getName().equals(Constant.SCOPE_SCOPES)) {

			List<Object> scopes=(List<Object>) object;

			List<Scope> result=new ArrayList<>();

			for (Object scope : scopes) {

				//不是Scope就跳过
				if (!(scope instanceof Scope)) {
					continue;
				}

				if (scope == null) {
					continue;
				}
				Scope temp=(Scope) scope;


				if (temp.getType() == null) {
					temp.setType("");
				}

				MColumnScope columnScope=queryScopeByType(temp.getType(), mTableScope.getColumns());

				if (columnScope == null) {
					continue;
				}

				//类型一致，就设置表名和列名
				temp.setType(columnScope.getType());
				temp.setTableName(columnScope.getTableName());
				temp.setColumn(columnScope.getName());

				result.add(temp);
			}

			parameter.setValue(result);

		}

	}

	/**
	 * 根据类型查询范围
	 *
	 * @param type    类型
	 * @param columns 类型字段
	 * @return
	 */
	protected MColumnScope queryScopeByType(String type, MColumnScope[] columns) {
		String compareType=type == null ? "" : type;
		for (MColumnScope columnScope : columns) {
			String cType=columnScope.getType() == null ? "" : columnScope.getType();
			String name=columnScope.getName();
			if (name == null) {
				continue;
			}
			if (cType.equals(compareType)) {
				return columnScope;
			}
		}
		return null;
	}
}
